package com.mtask.task.core;


import com.mtask.common.constants.TaskStatus;
import com.mtask.common.entity.task.TaskJob;
import com.mtask.task.core.action.ActionEnum;
import com.mtask.task.repository.TaskJobLogRepository;
import com.mtask.task.service.ActionService;
import org.quartz.*;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

@Component
public class CronScheduler {
    public static final String TASK = "task";
    public static final String REFERENCE_JOB = "referenceJob";
    public static final String TASK_JOB_LOG_REPOSITORY = "taskJobLogRepository";
    public static final String ACTION_SERVICE = "actionService";
    @Resource
    private Scheduler scheduler;
    @Resource
    private TaskJobLogRepository taskJobLogRepository;
    @Resource
    private ActionService actionService;

    private CronScheduler() {
    }


    public void addTaskJob(TaskJob task, Object referenceJob) {
        if (scheduler == null) return;
        if (TaskStatus.start.equals(task.getStatus())) {
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put(TASK, task);
            jobDataMap.put(REFERENCE_JOB, referenceJob);
            jobDataMap.put(TASK_JOB_LOG_REPOSITORY, taskJobLogRepository);
            jobDataMap.put(ACTION_SERVICE, actionService);
            for (ActionEnum actionEnum : ActionEnum.values()) {
                if (actionEnum.getName().equals(task.getReferenceType())) {
                    constructAndStartJob(task, jobDataMap, actionEnum.getAction().getClass());
                }
            }
        }
    }

    private void constructAndStartJob(TaskJob task, JobDataMap jobDataMap, Class<? extends Job> clz) {
        JobDetail jobDetail = JobBuilder.newJob(clz)
                .withIdentity(getSameJobKey(task))
                .usingJobData(jobDataMap)
                .build();
        CronTrigger cronTrigger = TriggerBuilder.newTrigger()
                .withIdentity(task.getName(), getSameGroup(task))
                .withSchedule(CronScheduleBuilder.cronSchedule(task.getCron()))
                .build();
        try {
            scheduler.scheduleJob(jobDetail, cronTrigger);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void addAllTaskJob(List<TaskJob> tasks, List<Object> jobs) {
        for (int i = 0; i < tasks.size() && i < jobs.size(); i++) {
            addTaskJob(tasks.get(i), jobs.get(i));
        }
    }

    public void deleteTaskJob(TaskJob taskJob) {
        if (scheduler == null) return;
        JobKey jobKey = getSameJobKey(taskJob);
        try {
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    private String getSameGroup(TaskJob task) {
        return String.format("%s-%s-%s", task.getTaskGroup().getId(), task.getTaskGroup().getGroupName(), task.getId());
    }

    private JobKey getSameJobKey(TaskJob taskJob) {
        return JobKey.jobKey(taskJob.getName(), getSameGroup(taskJob));
    }

    public void stopTaskJob(TaskJob taskJob) {
        if (scheduler == null) return;
        try {
            scheduler.pauseJob(getSameJobKey(taskJob));
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    public void stopAllTaskJob(List<TaskJob> jobs) {
        for (TaskJob job : jobs) {
            stopTaskJob(job);
        }
    }

    public void resumeTaskJob(TaskJob taskJob) {
        if (scheduler == null) return;
        try {
            scheduler.resumeJob(getSameJobKey(taskJob));
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    public void resumeAllTaskJob(List<TaskJob> jobs) {
        for (TaskJob job : jobs) {
            resumeTaskJob(job);
        }
    }

    public void deleteAllTaskJob(List<TaskJob> jobs) {
        if (scheduler == null) return;
        for (TaskJob job : jobs) {
            try {
                scheduler.deleteJob(getSameJobKey(job));
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }

    }
}

